#include "checkers/MemoryLeakCheck.h"

extern ReportSpace::Report external_bug_report;

//static llvm::cl::OptionCategory ToolingSampleCategory("Tooling Sample");

void MemoryLeakCheck::readConfig(string blockName) {
  std::unordered_map<std::string, std::string> ptrConfig =
      configure->getOptionBlock(blockName);
  interprocedural_analysis = "true";
  string allocFc = ptrConfig.find("allocFunc")->second;
  allocFc = allocFc.substr(1,allocFc.length()-2);
  string freeFc = ptrConfig.find("freeFunc")->second;
  freeFc = freeFc.substr(1,freeFc.length()-2);
  allocFunc = split_config_func(allocFc);
  freeFunc = split_config_func(freeFc);
  if(ptrConfig.count("functionpointer_analysis") > 0){
    functionpointer_analysis = ptrConfig.find("functionpointer_analysis")->second;
  }

  if(blockName == "MemoryLeakChecker" || blockName == "DoubleFreeChecker"){
    LEAKTYPE = ReportSpace::DefectName::MemoryLeak;
    FREETYPE = ReportSpace::DefectName::DoubleFree;
  }
}

void MemoryLeakCheck::analyzeDecl(const Stmt* stmt, const VarDecl*vd) { 
    if(!stmt){
      return;
    }
    auto bt=stmt->child_begin();
    for(;bt!=stmt->child_end();++bt)
    {
      analyzeDecl(*bt,vd);
    }
    if(const CallExpr* callExpr = dyn_cast<CallExpr>(stmt)) {
      FunctionDecl* func_decl = getFuncdeclWithFunctionPointer(callExpr,stmt);
      // std::vector<FunctionDecl*> fds = getFuncdeclWithFunctionPointer(callExpr,stmt);
      // bool inFirstIfTmp = inFirstIf;
      // bool inElseIfTmp = inElseIf;
      // bool inFirstCaseTmp = inFirstCase;
      // enterMultiFunc();
      // for(auto func_decl : fds){

        if(func_decl != nullptr){
          // handleLastFunc();
          // enterCurFunc();
          string funcCall = func_decl->getNameInfo().getName().getAsString();
          auto it = std::find(allocFunc.begin(),allocFunc.end(),funcCall);
          //is alloc func
          if(it != allocFunc.end()){       
              MemoryAddr* ma = new MemoryAddr(LINE);
              ma->field = FIELD;
              ma->lineno = LINE;
              ma->colno = COL;
              ma->type = &*it-&allocFunc[0];
              
              onePath->mem.insert(pair<int,MemoryAddr*>(LINE,ma));

              //whether the variable already exists 
              string declName = vd->getName().data();
              if(onePath->pointers.count(declName) == 0){
                MemoryPointer* mp = new MemoryPointer(declName);
                mp->field = FIELD;
                mp->lineno = LINE;
                mp->colno = COL;
                onePath->pointers.insert(pair<string,MemoryPointer*>(declName,mp));

                std::vector<MemoryAddr*> madr;
                madr.push_back(ma);
                onePath->pointerSet[declName] = madr;
              } else {
                if(onePath->pointerSet.count(declName) != 0){
                  std::vector<MemoryAddr*> ps_madr = onePath->pointerSet[declName];
                  bool hasLeakReport = false;
                  for(auto mad_iter = ps_madr.begin();
                  mad_iter != ps_madr.end();mad_iter++){
                    MemoryAddr* madr_tmp = *mad_iter;
                    if(madr_tmp->isreleased == false){
                      if(madr_tmp->num > 0) {
                        madr_tmp->num--;
                        if(madr_tmp->num == 0) {
                          MemoryAddr* oldma = madr_tmp;
                          oldma->isreleased = true;
                          if(!hasLeakReport && !inLeakReport(oldma->field,LINE)){
                            hasLeakReport = true;
                            string desc = "";
                            desc += "Memory leak after variable " + declName + " was changed";
                            ReportSpace::Defect *def = new ReportSpace::Defect(LEAKTYPE,
                                                                            ReportSpace::DefectType::Error,
                                                                            oldma->field,LINE, COL,
                                                                            declName);
                            def->addDesc(desc);
                            leakReport.push_back(def);
                            addLeakReport(oldma->field,LINE);
                          }
                        } else {
                          MemoryAddr* oldma = madr_tmp;
                          onePath->pointerSet[declName].clear();
                          for(auto map_iter = onePath->pointerSet.begin();
                          map_iter != onePath->pointerSet.end();map_iter++){
                            if(std::find(map_iter->second.begin(),map_iter->second.end(),oldma) 
                            != map_iter->second.end()){
                              onePath->mem.erase(oldma->id);
                              oldma->id = onePath->pointers[map_iter->first]->lineno;
                              oldma->lineno = onePath->pointers[map_iter->first]->lineno;
                              oldma->colno = onePath->pointers[map_iter->first]->colno;
                              onePath->mem.insert(pair<int,MemoryAddr*>(oldma->id,oldma));
                              break;
                            }
                          }
                        }
                      }  
                    }
                  }
                  std::vector<MemoryAddr*> madr;
                  madr.push_back(ma);
                  onePath->pointerSet[declName] = madr;
                }
              }
          } else {
            if(isPointerOrReferenceType(vd->getType().getTypePtr())){
              string declName = vd->getName().data();
              map<int,string> paramPtr;
              for (int i = 0; i < callExpr->getNumArgs(); i++) {
                  Expr *arg = const_cast<Expr*> (callExpr->getArg(i));
                  std::string argStr = getString_of_Expr(arg);
                  if(!isPointerOrReferenceType(arg->getType().getTypePtr())){
                    continue;
                  }
                  paramPtr.insert(pair<int,string>(i,argStr));
              }

              for(auto param_iter = paramPtr.begin();
                param_iter != paramPtr.end();param_iter++){
                if(onePath->pointerSet.count(param_iter->second) > 0){
                  param_addr_type.insert(pair<int,int>(param_iter->first,
                  (*onePath->pointerSet[param_iter->second].begin())->type));
                }
              }
              traverseCallFunc(const_cast<FunctionDecl*>(func_decl),paramPtr,declName);
            }
          }
        }

      //}
      // mergeFlow();
      // finishMultiFunc();
      // inFirstIf = inFirstIfTmp;
      // inElseIf = inElseIfTmp;
      // inFirstCase = inFirstCaseTmp;
    } else if(const DeclRefExpr* declExpr = dyn_cast<DeclRefExpr>(stmt)) {
      string declName = declExpr->getDecl()->getName().data();

      if (const VarDecl* vdr = dyn_cast<VarDecl>(declExpr->getDecl())) {
        string destName = vdr->getName().data();

        //alias
        if(isPointerOrReferenceType(vd->getType().getTypePtr())
        && isPointerOrReferenceType(vdr->getType().getTypePtr())){
          if(onePath->pointers.count(destName) > 0) {
            string declName = vd->getName().data();
            MemoryPointer* mp = new MemoryPointer(declName);
            mp->field = FIELD;
            mp->lineno = LINE;
            mp->colno = COL;
            onePath->pointers.insert(pair<string,MemoryPointer*>(declName,mp));

            onePath->pointerSet.insert(pair<string,std::vector<MemoryAddr*>>
              (declName,onePath->pointerSet[destName]));
            for(auto mav_iter = onePath->pointerSet[destName].begin();
            mav_iter != onePath->pointerSet[destName].end();mav_iter++){
              (*mav_iter)->num++;
            }
          }
        }
      }
    }
}

void MemoryLeakCheck::traverseStmt(const Stmt* stmt) {
    string desc = "";
    //alloc or alias
    if(strcmp(stmt->getStmtClassName(),"BinaryOperator")==0) {
      if (const BinaryOperator *b = dyn_cast<BinaryOperator>(stmt)) {

        if(b->getOpcodeStr().str()!="=")
        {
          return;
        }

        Expr *exprLHS = b->getLHS();
        string lexp = getString_of_Expr(exprLHS);

        Expr *exprRHS = b->getRHS();
        string rexp = getString_of_Expr(exprRHS);

        if(isPointerOrReferenceType(exprLHS->getType().getTypePtr()) 
        && isPointerOrReferenceType(exprRHS->getType().getTypePtr())){
          string ftmp = FIELD;
          string rName = ftmp.append(rexp);
          ftmp = FIELD;
          string lName = ftmp.append(lexp);
          if(FmName.count(rName) > 0){
            FuncHasFp.insert(pair<FunctionDecl*,bool>(onePath->F,true));
            if(FuncFp.count(onePath->F) == 0){
              vector<std::string> fpv;
              fpv.push_back(lName);
            } else {
              FuncFp[onePath->F].push_back(lName);
            }
            FmName.insert(pair<std::string,FunctionDecl*>(lName,FmName[rName]));
          }
        }

        //is alloc func
        if(CallExpr* callExpr = dyn_cast<CallExpr>(b->getRHS()->IgnoreParenCasts()->IgnoreImpCasts())) {
          //std::vector<FunctionDecl*> fds = getFuncdeclWithFunctionPointer(callExpr,stmt);
          FunctionDecl* callee_decl = getFuncdeclWithFunctionPointer(callExpr,stmt);
          // bool inFirstIfTmp = inFirstIf;
          // bool inElseIfTmp = inElseIf;
          // bool inFirstCaseTmp = inFirstCase;
          // enterMultiFunc();
          // for(auto callee_decl : fds){

            if(callee_decl != nullptr){
              // handleLastFunc();
              // enterCurFunc();
              string funcCall = callee_decl->getNameInfo().getName().getAsString();
              auto it = std::find(allocFunc.begin(),allocFunc.end(),funcCall);
              if(isPointerOrReferenceType(exprLHS->getType().getTypePtr())){
                string declName = "";
                if(DeclRefExpr* declExpr = dyn_cast<DeclRefExpr>(b->getLHS()->IgnoreParenCasts()->IgnoreImpCasts())){
                  declName = declExpr->getDecl()->getName().data();
                } else {
                  declName = lexp;
                }
                if(it != allocFunc.end()){  

                    MemoryAddr* ma = new MemoryAddr(LINE);
                    ma->field = FIELD;
                    ma->lineno = LINE;
                    ma->colno = COL;
                    ma->isreleased = false;
                    ma->type = &*it-&allocFunc[0];
                  
                    onePath->mem.insert(pair<int,MemoryAddr*>(LINE,ma));

                    //whether the variable already exists 
                    if(onePath->pointers.count(declName) == 0){
                      MemoryPointer* mp = new MemoryPointer(declName);
                      mp->field = FIELD;
                      mp->lineno = LINE;
                      mp->colno = COL;
                      onePath->pointers.insert(pair<string,MemoryPointer*>(declName,mp));

                      std::vector<MemoryAddr*> madr;
                      madr.push_back(ma);
                      onePath->pointerSet[declName] = madr;
                    } else {           
                      if(onePath->pointerSet.count(declName) != 0){
                        std::vector<MemoryAddr*> ps_madr = onePath->pointerSet[declName];
                        bool hasLeakReport = false;
                        for(auto mad_iter = ps_madr.begin();
                        mad_iter != ps_madr.end();mad_iter++){
                          MemoryAddr* madr_tmp = *mad_iter;
                          if(madr_tmp->isreleased == false){
                            if(madr_tmp->num > 0) {
                              madr_tmp->num--;
                              if(madr_tmp->num == 0) {
                                MemoryAddr* oldma = madr_tmp;
                                oldma->isreleased = true;
                                if(!hasLeakReport && !inLeakReport(oldma->field,LINE)){
                                  hasLeakReport = true;
                                  string desc = "";
                                  desc += "Memory leak after variable " + declName + " was changed";
                                  ReportSpace::Defect *def = new ReportSpace::Defect(LEAKTYPE,
                                                                                  ReportSpace::DefectType::Error,
                                                                                  oldma->field,LINE, COL,
                                                                                  declName);
                                  def->addDesc(desc);
                                  leakReport.push_back(def);
                                  addLeakReport(oldma->field,LINE);
                                }
                              } else {
                                MemoryAddr* oldma = madr_tmp;
                                onePath->pointerSet[declName].clear();
                                for(auto map_iter = onePath->pointerSet.begin();
                                map_iter != onePath->pointerSet.end();map_iter++){
                                  if(std::find(map_iter->second.begin(),map_iter->second.end(),oldma) 
                                  != map_iter->second.end()){
                                    onePath->mem.erase(oldma->id);
                                    oldma->id = onePath->pointers[map_iter->first]->lineno;
                                    oldma->lineno = onePath->pointers[map_iter->first]->lineno;
                                    oldma->colno = onePath->pointers[map_iter->first]->colno;
                                    onePath->mem.insert(pair<int,MemoryAddr*>(oldma->id,oldma));
                                    break;
                                  }
                                }
                              }
                            }  
                          }
                        }
                        std::vector<MemoryAddr*> madr;
                        madr.push_back(ma);
                        onePath->pointerSet[declName] = madr;
                      }
                    }
                } else if(isPointerOrReferenceType(exprLHS->getType().getTypePtr())) {
                  map<int,string> paramPtr;
                  for (int i = 0; i < callExpr->getNumArgs(); i++) {
                      Expr *arg = const_cast<Expr*> (callExpr->getArg(i));
                      std::string argStr = getString_of_Expr(arg);
                      if(!isPointerOrReferenceType(arg->getType().getTypePtr())){
                        continue;
                      }
                      paramPtr.insert(pair<int,string>(i,argStr));
                  }

                  for(auto param_iter = paramPtr.begin();
                    param_iter != paramPtr.end();param_iter++){
                    if(onePath->pointerSet.count(param_iter->second) > 0){
                      param_addr_type.insert(pair<int,int>(param_iter->first,
                      (*onePath->pointerSet[param_iter->second].begin())->type));
                    }
                  }
                  traverseCallFunc(const_cast<FunctionDecl*>(callee_decl),paramPtr,declName);
                }
              }
            }

          // }
          // mergeFlow();
          // finishMultiFunc();
          // inFirstIf = inFirstIfTmp;
          // inElseIf = inElseIfTmp;
          // inFirstCase = inFirstCaseTmp;
        } else if(isPointerOrReferenceType(exprLHS->getType().getTypePtr())
          && isPointerOrReferenceType(exprRHS->getType().getTypePtr())) {
          if(onePath->pointers.count(rexp) > 0) {
            if(onePath->pointers.count(lexp) == 0) {
              MemoryPointer* mp = new MemoryPointer(lexp);
              mp->field = FIELD;
              mp->lineno = LINE;
              mp->colno = COL;
              onePath->pointers.insert(pair<string,MemoryPointer*>(lexp,mp));
            }

            if(onePath->pointerSet.count(lexp) > 0){
              bool hasLeakReport = false;
              std::vector<MemoryAddr*> ps_madr = onePath->pointerSet[lexp];
              for(auto mav_iter = ps_madr.begin();
              mav_iter != ps_madr.end();mav_iter++){
                MemoryAddr* mad_tmp = *mav_iter;
                if(mad_tmp->isreleased == false){
                  mad_tmp->num--;
                  if(mad_tmp->num == 0) {
                    if(!hasLeakReport && !inLeakReport(mad_tmp->field,LINE)){
                      hasLeakReport = true;
                      desc += "Memory leak after variable " + lexp + " was changed";
                      ReportSpace::Defect *def = new ReportSpace::Defect(LEAKTYPE,
                                                                      ReportSpace::DefectType::Error,
                                                                      mad_tmp->field,LINE, COL,
                                                                      lexp);
                      def->addDesc(desc);
                      leakReport.push_back(def);
                      addLeakReport(mad_tmp->field,LINE);
                    }
                    mad_tmp->isreleased = true;
                  } else {
                    MemoryAddr* oldma = mad_tmp;
                    onePath->pointerSet[lexp].clear();
                    for(auto map_iter = onePath->pointerSet.begin();
                    map_iter != onePath->pointerSet.end();map_iter++){
                      if(std::find(map_iter->second.begin(),map_iter->second.end(),oldma) 
                        != map_iter->second.end()){
                        onePath->mem.erase(oldma->id);
                        oldma->id = onePath->pointers[map_iter->first]->lineno;
                        oldma->lineno = onePath->pointers[map_iter->first]->lineno;
                        oldma->colno = onePath->pointers[map_iter->first]->colno;
                        onePath->mem.insert(pair<int,MemoryAddr*>(oldma->id,oldma));
                        break;
                      }
                    }
                  }
                }
              }
              onePath->pointerSet[lexp] = onePath->pointerSet[rexp];
            } else {
              onePath->pointerSet.insert(pair<string,vector<MemoryAddr*>>
                (lexp,onePath->pointerSet[rexp]));
            }

            for(auto mav_iter = onePath->pointerSet[rexp].begin();
            mav_iter != onePath->pointerSet[rexp].end();mav_iter++){
              (*mav_iter)->num++;
            }
          }
        }
      }
    } else if(strcmp(stmt->getStmtClassName(),"DeclStmt")==0) {
      if (const DeclStmt *F = dyn_cast<DeclStmt>(stmt)) {
        if (!F->isSingleDecl() || !F->getSingleDecl())
        {
            return;
        }
        if(const VarDecl*v = dyn_cast<VarDecl>(F->getSingleDecl())){
          analyzeDecl(stmt,v);
        }
      }
    } else if(strcmp(stmt->getStmtClassName(),"CallExpr")==0) {

      traverseCallExpr(stmt);

    } else if(strcmp(stmt->getStmtClassName(),"ReturnStmt")==0) {
      if(const ReturnStmt *returnStmt = dyn_cast<ReturnStmt>(stmt)) {
        if(const Expr *returnValue = returnStmt->getRetValue()){
            if(isPointerOrReferenceType(returnValue->getType().getTypePtr())){
              string returnName = getString_of_Expr(const_cast<Expr *>(returnValue));

              if(onePath->pointers.count(returnName) > 0){
                  onePath->pointers[returnName]->type = "return";
              }

              if(onePath->pointerSet.count(returnName) > 0){
                for(auto mav_iter = onePath->pointerSet[returnName].begin();
                mav_iter != onePath->pointerSet[returnName].end();mav_iter++){
                  (*mav_iter)->isreturned = true;
                }
              }
            }
        }
        handleReturn();
      }
    }
}

void MemoryLeakCheck::traverseCallExpr(const Stmt* stmt){
  string desc = "";
  if(const CallExpr* callExpr = dyn_cast<CallExpr>(stmt)){
    FunctionDecl* func_decl = getFuncdeclWithFunctionPointer(callExpr,stmt);
    //std::vector<FunctionDecl*> fds = getFuncdeclWithFunctionPointer(callExpr,stmt);
    // bool inFirstIfTmp = inFirstIf;
    // bool inElseIfTmp = inElseIf;
    // bool inFirstCaseTmp = inFirstCase;
    // enterMultiFunc();
    // for(auto func_decl : fds){

      if(func_decl != nullptr){
        // handleLastFunc();
        // enterCurFunc();
        string funcCall = func_decl->getNameAsString();
        //string funcCall = func_decl->getNameInfo().getName().getAsString();
        map<int,string> paramPtr;
        for (int i = 0; i < callExpr->getNumArgs(); i++) {
            Expr *arg = const_cast<Expr*>(callExpr->getArg(i));
            std::string argStr = getString_of_Expr(arg);
            if(!isPointerOrReferenceType(arg->getType().getTypePtr())){
              continue;
            }
            paramPtr.insert(pair<int,string>(i,argStr));
        }
        
        if(paramPtr.size() > 0) {    

          if(std::find(freeFunc.begin(),freeFunc.end(),funcCall) != freeFunc.end()){
            //free函数的参数位置可能需要改变
            std::string argStr = paramPtr[0];

            if(onePath->pointers.count(argStr) != 0) {
              if(onePath->pointerSet.count(argStr) != 0){
                bool hasFreeReport = false;
                for(auto mav_iter = onePath->pointerSet[argStr].begin();
                mav_iter != onePath->pointerSet[argStr].end();mav_iter++){
                  if((*mav_iter)->type == -1 || funcCall == freeFunc[(*mav_iter)->type]) {
                    if((*mav_iter)->isreleased == false) {
                      (*mav_iter)->isreleased = true;
                      handleFreeState(ifLevel,(*mav_iter));

                      if(BLOCKNAME == "DoubleFreeChecker") {
                        if(forLevel > 0 && !hasFreeReport){
                          if(forPathTmp[forLevel]->mem.count((*mav_iter)->id) > 0){
                            if((*forPathTmp[forLevel]->mem[(*mav_iter)->id]).isreleased == false){
                              hasFreeReport = true;
                              desc += "Double in variable " + argStr;
                              ReportSpace::Defect *def = new ReportSpace::Defect(FREETYPE,
                                                                          ReportSpace::DefectType::Error,
                                                                          FIELD,LINE,COL,
                                                                          argStr);
                              def->addDesc(desc);
                              freeReport.push_back(def);
                            }
                          }
                        }
                      }

                    } else if((*mav_iter)->isreleased == true && !hasFreeReport){
                      if(BLOCKNAME == "DoubleFreeChecker") {
                        desc += "Double in variable " + argStr;
                        ReportSpace::Defect *def = new ReportSpace::Defect(FREETYPE,
                                                                    ReportSpace::DefectType::Error,
                                                                    FIELD,LINE,COL,
                                                                    argStr);
                        def->addDesc(desc);
                        freeReport.push_back(def);
                        hasFreeReport = true;
                      }
                    }
                  }
                }
              }
            }
          } else {
            if(interprocedural_analysis == "true"){
              for(auto param_iter = paramPtr.begin();
                param_iter != paramPtr.end();param_iter++){
                if(onePath->pointerSet.count(param_iter->second) > 0){
                  param_addr_type.insert(pair<int,int>(param_iter->first,
                  (*onePath->pointerSet[param_iter->second].begin())->type));
                }
              }
              traverseCallFunc(const_cast<FunctionDecl*>(func_decl),paramPtr,"");
            }        
          }
        }
      }

    // }
    // mergeFlow();
    // finishMultiFunc();
    // inFirstIf = inFirstIfTmp;
    // inElseIf = inElseIfTmp;
    // inFirstCase = inFirstCaseTmp;
  }
}

void MemoryLeakCheck::traverseCallFunc(FunctionDecl *func_decl,map<int,string> paramPtr,string dstName){
    if(func_decl == nullptr) {
      return;
    }
    ASTFunction *callee = call_graph->getFunction(func_decl);
    if(!IgnoreFunc(callee) && MemoryFuncList.find(func_decl) == MemoryFuncList.end()){
      string fieldTmp = FIELD;
      int lineTmp = LINE;
      int colTmp = COL; 
      FuncMemory* oneTmp = new FuncMemory(onePath);
      map<int,FuncMemory*> onePathTmpCopy = onePathTmp;
      map<int,FuncMemory*> forPathTmpCopy = forPathTmp;
      map<int,std::vector<FuncMemory*>> ifStatesCopy =  ifStates;
      map<int,map<MemoryAddr*,BranchStatus>> madrStatesCopy = madrStates;
      map<int,bool> hasDefaultCopy = hasDefault;
      int ifLevelCopy = ifLevel;
      int forLevelCopy = forLevel;

      handleFunctionDecl(func_decl);

      onePath = new FuncMemory(oneTmp);
      onePathTmp = onePathTmpCopy;
      forPathTmp = forPathTmpCopy;
      ifStates = ifStatesCopy;
      madrStates = madrStatesCopy;
      hasDefault = hasDefaultCopy;
      ifLevel = ifLevelCopy;
      forLevel = forLevelCopy;
      oneTmp = nullptr;
      COL = colTmp;
      LINE = lineTmp;
      FIELD = fieldTmp;
    }

    //优化，不用分析函数赋为默认值（null)，否则每次都判断一次
    if(MemoryFuncList.count(func_decl) > 0){
      FuncMemory* call_fm = MemoryFuncList[func_decl];
      updateFuncMemory(call_fm,func_decl,paramPtr,dstName);
    }

    return;
}

void MemoryLeakCheck::check(string blockName) {
  BLOCKNAME = blockName;
  readConfig(blockName);

  std::vector<ASTFunction *> funcs = manager->getFunctions();
  unsigned funcNums = manager->getFunctions().size();
  int i = 0;

  for (ASTFunction *F : funcs) {
    if(!IgnoreFunc(F)){
      updateFunctionPointer(F);
      FunctionDecl *func_decl = manager->getFunctionDecl(F);
      handleFunctionDecl(func_decl);
    }
    i++;
    process_bar(float(i) / funcNums);
  }

  if(BLOCKNAME == "MemoryLeakChecker") {
    for(int i = 0;i < leakReport.size();i++) {
      external_bug_report.addToReport(leakReport[i]);
    }
  }

  if(BLOCKNAME == "DoubleFreeChecker") {
    for (int i = 0;i < freeReport.size();i++) {
      external_bug_report.addToReport(freeReport[i]);
    } 
  }
}

void MemoryLeakCheck::updateFunctionPointer(ASTFunction* F){
  if(functionpointer_analysis == "true"){
    FunctionDecl* FD = manager->getFunctionDecl(F);
    if(FD != nullptr && FD->hasBody()){
      std::vector<std::pair<ASTFunction *, int64_t>> callers =
          call_graph->getChildrenWithCallsite(F);
      if(callers.size() == 0){
        return;
      }
      funPointerStates.insert(pair<FunctionDecl*,
      std::vector<std::pair<ASTFunction *, int64_t>>>(FD,callers));
      for (auto caller : callers) {
        // find call site
        if(manager->getFunctionDecl(caller.first)->hasBody()){
          FunctionDecl *tmp_fd=manager->getFunctionDecl(caller.first)->getDefinition();
          caller.first=manager->getASTFunction(tmp_fd);
        }
      }
    }
  }
}

std::string MemoryLeakCheck::getString_of_Expr(Expr *expr) {
  LangOptions L0;
  L0.CPlusPlus = 1;
  std::string buffer1;
  llvm::raw_string_ostream strout1(buffer1);
  expr->printPretty(strout1, nullptr, PrintingPolicy(L0));
  return strout1.str();
}

std::string MemoryLeakCheck::getString_of_Stmt(Stmt *stmt) {
  LangOptions L0;
  L0.CPlusPlus = 1;
  std::string buffer1;
  llvm::raw_string_ostream strout1(buffer1);
  stmt->printPretty(strout1, nullptr, PrintingPolicy(L0));
  return strout1.str();
}

std::vector<string> MemoryLeakCheck::split_config_func(string tmp) {

  vector<string> res;  
  if("" == tmp) 
    return res;
  string delim = ",";
	char * strs = new char[tmp.length() + 1] ; 
	strcpy(strs, tmp.c_str());   
 
	char * d = new char[delim.length() + 1];  
	strcpy(d, delim.c_str());  
 
	char *p = strtok(strs, d);  
	while(p) {  
		string s = p; 
		res.push_back(s.substr(1,s.length()-2)); 
		p = strtok(NULL, d);  
	} 
  return res;
}

std::string MemoryLeakCheck::split_call_of_Expr(Expr *expr) {
  string exprName = getString_of_Expr(expr);
  string funName = exprName.substr(0,exprName.find("("));
  string ftmp = FIELD;
  return ftmp.append(funName);
}

bool MemoryLeakCheck::isFunctionPointer(VarDecl *D) {
  return D->getType().getTypePtr()->isPointerType() ||
          D->getType().getTypePtr()->isReferenceType() ||
          D->getType()->isFunctionPointerType() ||
          D->getType()->isMemberFunctionPointerType();
}

bool MemoryLeakCheck::isPointerOrReferenceType(const clang::Type* T) {
  return T->isPointerType() ||
        T->isReferenceType();
}

void MemoryLeakCheck::updateFuncMemory(FuncMemory* dst,
const FunctionDecl *func_decl,
map<int,string> paramPtr,string dstName){
    string desc = "";
    bool isreturn = false;
    string returnName;
    if(func_decl->getReturnType().getAsString() != "void"
     && isPointerOrReferenceType(func_decl->getReturnType().getTypePtr())){
      map<std::string,MemoryPointer*> ptmp = dst->pointers;
      for(auto p_iter = ptmp.begin();
      p_iter != ptmp.end();p_iter++){
        if(p_iter->second->type == "return"){
          isreturn = true;
          returnName = p_iter->first;
          break;
        }
      }
    }

    FuncMemory* callFm = dst;

    for(auto iter = paramPtr.begin();iter != paramPtr.end();iter++) {
      if(iter->first < func_decl->getNumParams()){
        const ParmVarDecl *pDecl = func_decl->getParamDecl(iter->first);
        string arg_src = iter->second;
        string arg_dest = pDecl->getNameAsString();

        if(onePath->pointerSet.count(arg_src) == 0){
          continue;
        }

        if(callFm->pointerSet.count(arg_dest) > 0){
          if(*callFm->pointerSet[arg_dest].begin() != nullptr){
            if((*callFm->pointerSet[arg_dest].begin())->isreleased == true){
              bool hasFreeReport = false;
              for(auto mad_iter = onePath->pointerSet[arg_src].begin();
                mad_iter != onePath->pointerSet[arg_src].end();mad_iter++){
                  if((*mad_iter)->isreleased == true){
                    if(!hasFreeReport){
                      hasFreeReport = true;
                      desc += "Double in variable " + arg_src;
                      ReportSpace::Defect *def = new ReportSpace::Defect(FREETYPE,
                                                                  ReportSpace::DefectType::Error,
                                                                  FIELD,LINE,COL,
                                                                  arg_src);
                      def->addDesc(desc);
                      freeReport.push_back(def);
                    }
                  } else {
                    (*mad_iter)->isreleased = true;
                    handleFreeState(ifLevel,(*mad_iter));
                  }
              }
            }
          }
        }
      }
    }

    if(isreturn == true){
      MemoryAddr* ma = new MemoryAddr(callFm->pointerSet[returnName][0]);
      ma->id = LINE;
      ma->field = FIELD;
      ma->lineno = LINE;
      ma->colno = COL;
      ma->isreturned = false;

      if(onePath->pointers.count(dstName) == 0){
        MemoryPointer* mp = new MemoryPointer(dstName);
        mp->field = FIELD;
        mp->lineno = LINE;
        mp->colno = COL;
        onePath->pointers.insert(pair<string,MemoryPointer*>(dstName,mp));

        onePath->mem.insert(pair<int,MemoryAddr*>(LINE,ma));
        std::vector<MemoryAddr*> madr;
        madr.push_back(ma);
        onePath->pointerSet.insert(pair<string,std::vector<MemoryAddr*>>(dstName,madr));
      } else {
        if(onePath->pointerSet.count(dstName) != 0){
          
          std::vector<MemoryAddr*> ps_madr = onePath->pointerSet[dstName];
          bool hasLeakReport = false;
          for(auto mad_iter = ps_madr.begin();
          mad_iter != ps_madr.end();mad_iter++){
            MemoryAddr* madr_tmp = *mad_iter;
            if(madr_tmp->isreleased == false){
              if(madr_tmp->num > 0) {
                madr_tmp->num--;
                if(madr_tmp->num == 0) {
                  MemoryAddr* oldma = madr_tmp;
                  oldma->isreleased = true;
                  if(!hasLeakReport && !inLeakReport(oldma->field,LINE)){
                    hasLeakReport = true;
                    string desc = "";
                    desc += "Memory leak after variable " + dstName + " was changed";
                    ReportSpace::Defect *def = new ReportSpace::Defect(LEAKTYPE,
                                                                    ReportSpace::DefectType::Error,
                                                                    oldma->field,LINE, COL,
                                                                    dstName);
                    def->addDesc(desc);
                    leakReport.push_back(def);
                    addLeakReport(oldma->field,LINE);
                  }
                } else {
                  MemoryAddr* oldma = madr_tmp;
                  onePath->pointerSet[dstName].clear();
                  for(auto map_iter = onePath->pointerSet.begin();
                  map_iter != onePath->pointerSet.end();map_iter++){
                    if(std::find(map_iter->second.begin(),map_iter->second.end(),oldma) 
                      != map_iter->second.end()){
                        onePath->mem.erase(oldma->id);
                        oldma->id = onePath->pointers[map_iter->first]->lineno;
                        oldma->lineno = onePath->pointers[map_iter->first]->lineno;
                        oldma->colno = onePath->pointers[map_iter->first]->colno;
                        onePath->mem.insert(pair<int,MemoryAddr*>(oldma->id,oldma));
                        break;
                      }
                  }
                }
              }  
            }

          }
          onePath->mem.insert(pair<int,MemoryAddr*>(LINE,ma));
          onePath->pointerSet[dstName].clear();
          onePath->pointerSet[dstName].push_back(ma);

        }
      }
    }
}

FunctionDecl* MemoryLeakCheck::getFuncdeclWithFunctionPointer(const CallExpr* callExpr,const Stmt *stmt){
//void MemoryLeakCheck::getFuncdeclWithFunctionPointer(const CallExpr* callExpr,const Stmt *stmt){
  FunctionDecl *func_decl = nullptr;
  //std::vector<FunctionDecl*> fds;
  func_decl = const_cast<FunctionDecl*>(callExpr->getDirectCallee());
  if(functionpointer_analysis == "true") {
    if(func_decl == nullptr){
      if(funPointerStates.count(onePath->F) > 0){
        std::vector<std::pair<ASTFunction *, int64_t>> callers = funPointerStates[onePath->F];
        for(auto caller = callers.rbegin();caller != callers.rend();caller++){
        //for(auto caller:callers){
          Stmt *stmts = common::getStmtInFunctionWithID(onePath->F,caller->second);
          if(stmts == stmt){
            //stmts->dump();
            func_decl = manager->getFunctionDecl(caller->first);
            //fds.push_back(func_decl);
            break;
          }
        }
      }
      // for(auto fps : funPointerStates){
        
      //   for(auto caller:callers){
      //     Stmt *stmts = common::getStmtInFunctionWithID(manager->getFunctionDecl(caller.first),caller.second);
      //     stmts->dump();
      //     if(stmts == stmt){
      //       func_decl = fps.first;
      //       break;
      //     }
      //   }
      // }
    // } else {
    //   fds.push_back(func_decl);
    // }
    // if(fds.size() > 0){
    //   callstmtStates.insert(pair<FunctionDecl*,std::vector<FunctionDecl*>>(onePath->F,fds));
    // }
    }
  }
  return func_decl;
}

void MemoryLeakCheck::handleFunctionDecl(FunctionDecl *FD) {
    std::string funcName = FD->getNameInfo().getName().getAsString();
    clang::SourceManager&srcMgr(FD->getASTContext().getSourceManager());
    FIELD = srcMgr.getFilename(srcMgr.getLocForStartOfFile(srcMgr.getMainFileID()));
    std::string ftmp = FIELD;
    std::string allName = ftmp.append(funcName);
    FmName.insert(pair<std::string,FunctionDecl*>(allName,FD));
    if(FD->hasBody() && FuncVisit.count(FD) == 0) {
      LINE = srcMgr.getExpansionLineNumber(FD->getBeginLoc());
      COL = srcMgr.getExpansionColumnNumber(FD->getBeginLoc());
      enterFunctionScope(FD);
      handleParam(FD);
      const clang::CompoundStmt*CS=llvm::cast<clang::CompoundStmt>(FD->getBody());
      for (auto It = CS->child_begin(); It != CS->child_end(); It++) {
        handleStatement(*It,srcMgr);
      }
      handleFunctionEnd();
      finishFunctionScope(FD);
      //if(FuncHasFp.count(FD) == 0){
      MemoryFuncList.insert(pair<FunctionDecl*,FuncMemory*>(FD,new FuncMemory(onePath)));
      //}
    }
} 

void MemoryLeakCheck::handleParam(FunctionDecl *FD) {
    map<std::string,std::vector<MemoryAddr*>> param_pointerSet;
    map<int,MemoryAddr*>param_mem;
    map<std::string,MemoryPointer*>param_pointers;

    if(!FD->param_empty()){
      int index = 0;
      for (auto param = FD->param_begin(); param != FD->param_end(); ++param) {
        ParmVarDecl *parm = *param;
        //处理函数的函数指针参数
        if (isFunctionPointer(parm)) {
          MemoryPointer* p = new MemoryPointer(parm->getNameAsString());
          p->field = FIELD;
          p->lineno = LINE;
          p->colno = COL;
          p->type = "param";

          MemoryAddr* ma = new MemoryAddr(LINE);
          ma->field = FIELD;
          ma->lineno = LINE;
          ma->colno = COL;
          ma->isparam = true;
          ma->type = -1;
          if(param_addr_type.size() > index){
            ma->type = param_addr_type[index];
          } 

          param_pointers.insert(pair<string,MemoryPointer*>(parm->getNameAsString(),p));
          param_mem.insert(pair<int,MemoryAddr*>(LINE,ma));
          std::vector<MemoryAddr*> madr;
          madr.push_back(ma);
          param_pointerSet.insert(pair<std::string,std::vector<MemoryAddr*>>(parm->getNameAsString(),madr));
        }
        index++;
      }
    }    
    param_addr_type.clear();

    onePath = new FuncMemory(FD);
    onePath->pointers = param_pointers;
    onePath->mem = param_mem;
    onePath->pointerSet = param_pointerSet;

    onePathTmp[0] = new FuncMemory(onePath);
}

void MemoryLeakCheck::finishFunctionScope(FunctionDecl *FD) {
    for(auto ps_iter = onePath->pointerSet.begin();
      ps_iter != onePath->pointerSet.end();ps_iter++){
        string declName = ps_iter->first;
        std::vector<MemoryAddr*> madr = ps_iter->second;
        BranchStatus cur_state = BranchStatus::INIT;

        for(auto mem_iter = madr.begin();
          mem_iter != madr.end();mem_iter++){ 
            if((*mem_iter)->isreleased == false && (*mem_iter)->isreturned == false
            && (*mem_iter)->isparam == false){
              if(leakMap.count(*(*mem_iter)) == 0){
                string desc = "Memory leak in variable " + declName;
                ReportSpace::Defect *def = new ReportSpace::Defect(LEAKTYPE,
                                                                ReportSpace::DefectType::Error,
                                                                (*mem_iter)->field,(*mem_iter)->lineno, (*mem_iter)->colno,
                                                                declName);
                def->addDesc(desc);
                leakReport.push_back(def);
                leakMap.insert(pair<MemoryAddr,ReportSpace::Defect *>(*(*mem_iter),def));
              }
              if(cur_state == BranchStatus::INIT){
                cur_state = BranchStatus::NO_FREE;
              } else if(cur_state == BranchStatus::ALL_FREE){
                cur_state = BranchStatus::POSSIBLE_FREE;
              }
            } else {
              if((*mem_iter)->isreturned == true || (*mem_iter)->isparam == true){
                if((*mem_iter)->isreleased == true){
                  if(cur_state == BranchStatus::INIT){
                    cur_state = BranchStatus::ALL_FREE;
                  } else if(cur_state == BranchStatus::NO_FREE){
                    cur_state = BranchStatus::POSSIBLE_FREE;
                  }
                } else {
                  if(cur_state == BranchStatus::INIT){
                    cur_state = BranchStatus::NO_FREE;
                  } else if(cur_state == BranchStatus::ALL_FREE){
                    cur_state = BranchStatus::POSSIBLE_FREE;
                  }
                }
              } else {
                if(cur_state == BranchStatus::INIT){
                  cur_state = BranchStatus::ALL_FREE;
                } else if(cur_state == BranchStatus::NO_FREE){
                  cur_state = BranchStatus::POSSIBLE_FREE;
                }
              }
            }
        }

        std::vector<MemoryAddr*> new_madr;
        if(cur_state == BranchStatus::NO_FREE || cur_state == BranchStatus::ALL_FREE){
          MemoryAddr* ma_tmp = new MemoryAddr(*onePath->pointerSet[declName].begin());
          new_madr.push_back(ma_tmp);
        } else if(cur_state == BranchStatus::POSSIBLE_FREE){
          MemoryAddr* ma_tmp = new MemoryAddr(LINE);
          if(BLOCKNAME == "MemoryLeakChecker") {
            ma_tmp->isreleased = false;
          }

          if(BLOCKNAME == "DoubleFreeChecker") {
            ma_tmp->isreleased = true;
          }
          new_madr.push_back(ma_tmp);
        }
        onePath->pointerSet[declName].clear();
        onePath->pointerSet[declName] = new_madr;
    }

    handleFunctionPointer(FD);
}

void MemoryLeakCheck::handleStatement(const clang::Stmt *S,SourceManager&srcMgr){
    COL=srcMgr.getSpellingColumnNumber(S->getBeginLoc());
    LINE=srcMgr.getSpellingLineNumber(S->getBeginLoc());
    if(S==nullptr){
        return;
    }
    if(clang::isa<clang::IfStmt>(S)){
      const clang::IfStmt *IS=llvm::cast<clang::IfStmt>(S);
      bool inFirstIfTmp = inFirstIf;
      bool inElseIfTmp = inElseIf;
      //if嵌套或者if初始化
      bool ifInit = false;
      if(ifStates.count(0) == 0){
        if(!inElseIf || ifLevel+1 > ifStates.size())
          ifInit = true;
      } else {
        if(!inElseIf || ifLevel + 2 > ifStates.size())
          ifInit = true;
      }
      if(ifInit){
        inFirstIf = true;
        inElseIf = false;
        std::vector<FuncMemory*> ifState;
        ifStates[ifLevel+1] = ifState;

        map<MemoryAddr*,BranchStatus> madrState;
        madrStates[ifLevel+1] = madrState;
      }

      enterIfScope(IS);

      if(clang::isa<clang::CompoundStmt>(IS->getThen())){
        bool inFirstTmp = inFirstIf;
        bool inElseTmp = inElseIf;
        const clang::CompoundStmt* CS=llvm::cast<clang::CompoundStmt>(IS->getThen());
        for (auto It = CS->child_begin(); It != CS->child_end(); It++) {
          handleStatement(*It,srcMgr);
        }
        inFirstIf = inFirstTmp;
        inElseTmp = inElseTmp;
      }else{
        handleStatement(IS->getThen(),srcMgr);
      }

      if(IS->getElse()) {
          handleNoFree();
          bool inFirstTmp = inFirstIf;
          enterElseScope(IS);
          if (clang::isa<clang::CompoundStmt>(IS->getElse())) {
              bool inElseTmp = inElseIf;
              const clang::CompoundStmt *CS = llvm::cast<clang::CompoundStmt>(IS->getElse());
              for (auto It = CS->child_begin(); It != CS->child_end(); It++) {
                  handleStatement(*It,srcMgr);
              }
              inElseTmp = inElseTmp;
            
          } else {
            inElseIfTmp = inElseIf;
            bool inElseTmp = inElseIf;
            enterElseIfScope(IS);
            handleStatement(IS->getElse(),srcMgr);
            finishElseIfScope(IS);
            inElseIf = inElseTmp;
          }
          handleNoFree();
          inFirstIf = inFirstTmp;
      } else {
        handleNoElse();
      }

      if(ifStates.count(ifLevel) > 0){
        ifStates[ifLevel].push_back(new FuncMemory(onePath));
      }
      mergeFlow();//函数结束要将ifstate对应状态初始化
      inElseIf = inElseIfTmp;
      inFirstIf = inFirstIfTmp;
      finishIfScope(IS);
    } else if(clang::isa<clang::SwitchStmt>(S)){
      const clang::SwitchStmt *SS=llvm::cast<clang::SwitchStmt>(S);

      bool inFirstIfTmp = inFirstIf;
      bool inElseIfTmp = inElseIf;
      bool inFirstCaseTmp = inFirstCase;

      enterSwitchScope(SS);
      if(clang::isa<clang::CompoundStmt>(SS->getBody())){
        const clang::CompoundStmt* CS=llvm::cast<clang::CompoundStmt>(SS->getBody());
        for (auto It = CS->child_begin(); It != CS->child_end(); It++) {
          handleStatement(*It,srcMgr);
        }
      }else{
        handleStatement(SS->getBody(),srcMgr);
      }
      handleDefault();
      mergeFlow();
      finishSwitchScope(SS);
      inFirstIf = inFirstIfTmp;
      inElseIf = inElseIfTmp;
      inFirstCase = inFirstCaseTmp;
    } else if(clang::isa<clang::CaseStmt>(S)){
      const clang::CaseStmt *CS=llvm::cast<clang::CaseStmt>(S);
      handleLastCase();
      enterCaseStmt(CS);
      if(clang::isa<clang::CompoundStmt>(CS->getSubStmt())){
        const clang::CompoundStmt* CoS=llvm::cast<clang::CompoundStmt>(CS->getSubStmt());
        for (auto It = CoS->child_begin(); It != CoS->child_end(); It++) {
          handleStatement(*It,srcMgr);
        }
      }else{
        handleStatement(CS->getSubStmt(),srcMgr);
      }

    } else if(clang::isa<clang::DefaultStmt>(S)){
      const clang::DefaultStmt *DS=llvm::cast<clang::DefaultStmt>(S);
      handleLastCase();
      enterDefaultStmt(DS);
      if(clang::isa<clang::CompoundStmt>(DS->getSubStmt())){
          const clang::CompoundStmt* CS=llvm::cast<clang::CompoundStmt>(DS->getSubStmt());
          for (auto It = CS->child_begin(); It != CS->child_end(); It++) {
            handleStatement(*It,srcMgr);
          }
      }else{
          handleStatement(DS->getSubStmt(),srcMgr);
      }
    } else if(clang::isa<clang::WhileStmt>(S)){
        const clang::WhileStmt *WS=llvm::cast<clang::WhileStmt>(S);
        enterWhileScope(WS);
        if(clang::isa<clang::CompoundStmt>(WS->getBody())){
          const clang::CompoundStmt* CS=llvm::cast<clang::CompoundStmt>(WS->getBody());
          for (auto It = CS->child_begin(); It != CS->child_end(); It++) {
            handleStatement(*It,srcMgr);
          }
        }else{
          handleStatement(WS->getBody(),srcMgr);
        }
        finishWhileScope(WS);
    } else if(clang::isa<clang::DoStmt>(S)){
        const clang::DoStmt *DS=llvm::cast<clang::DoStmt>(S);
        enterDoScope(DS);
        if(clang::isa<clang::CompoundStmt>(DS->getBody())){
          const clang::CompoundStmt* CS=llvm::cast<clang::CompoundStmt>(DS->getBody());
          for (auto It = CS->child_begin(); It != CS->child_end(); It++) {
            handleStatement(*It,srcMgr);
          }
        }else{
          handleStatement(DS->getBody(),srcMgr);
        }
        finishDoScope(DS);
    }else if(clang::isa<clang::ForStmt>(S)){
        const clang::ForStmt *FS=llvm::cast<clang::ForStmt>(S);
        enterForScope(FS);
        auto Body=FS->getBody();
        if(clang::isa<clang::CompoundStmt>(Body)){
          auto CS=llvm::cast<clang::CompoundStmt>(Body);
          for(auto It=CS->child_begin();It!=CS->child_end();It++){
            handleStatement(*It,srcMgr);
          }
        }else{
          handleStatement(Body,srcMgr);
        }
        finishForScope(FS);
    } else {
      traverseStmt(S);
    }
}

bool MemoryLeakCheck::IgnoreFunc(ASTFunction *F){
    auto func_decl = manager->getFunctionDecl(F);
    if(func_decl == nullptr){
      return true;
    }

    //used to avoid analysis library func, maybe not use
    if (F->getFunctionName().find("std::") != std::string::npos){
      return true;
    }

    if (func_decl->getBeginLoc()
            .printToString(func_decl->getASTContext().getSourceManager())
            .find("/usr/lib/gcc") != std::string::npos){
            return true;
          }

    if (func_decl->getBeginLoc()
          .printToString(func_decl->getASTContext().getSourceManager())
          .find("/usr/include") != std::string::npos){
            return true;
          }

    SourceLocation SL = func_decl->getLocation();
    SourceManager &SM = func_decl->getASTContext().getSourceManager();
    std::string analysisSystemHeader = "false";

    if (analysisSystemHeader == "false")
      if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL) ||
          SM.isInSystemMacro(SL)) {
        return true;
      }

    string funcName = func_decl->getNameInfo().getName().getAsString();
    if(std::find(allocFunc.begin(),allocFunc.end(),funcName) != allocFunc.end() 
    || std::find(freeFunc.begin(),freeFunc.end(),funcName) != freeFunc.end()){
      return true;
    }

    if(MemoryFuncList.find(func_decl) != MemoryFuncList.end()){
      return true;
    }

    return false;
}

void MemoryLeakCheck::enterFunctionScope(FunctionDecl *FD){
  ifStates.clear();
  madrStates.clear();
  onePathTmp.clear();
  forPathTmp.clear();
  onePath = nullptr;
  inFirstIf = true;
  inElseIf = false;
  inFirstCase = true;
  inReturn = false;
  ifLevel = 0;
  forLevel = 0;
  FuncVisit.insert(pair<FunctionDecl*,bool>(FD,true));
}

void MemoryLeakCheck::enterIfScope(const clang::IfStmt *IS){
  ifLevel += 1;
  if(inFirstIf){
    onePathTmp[ifLevel] = new FuncMemory(onePath);
  }
  onePath = nullptr;
  onePath = new FuncMemory(onePathTmp[ifLevel]);
  handleIfCond(IS);
}

void MemoryLeakCheck::enterElseScope(const clang::IfStmt *IS){
  inFirstIf = false;
  ifStates[ifLevel].push_back(new FuncMemory(onePath));
  onePath = nullptr;
  onePath = new FuncMemory(onePathTmp[ifLevel]);
}

void MemoryLeakCheck::enterElseIfScope(const clang::IfStmt *IS){
  ifLevel -= 1;
  inElseIf = true;
}

void MemoryLeakCheck::enterMultiFunc(){
  ifLevel += 1;
  onePathTmp[ifLevel] = new FuncMemory(onePath);

  inFirstIf = true;
  inElseIf = false;
  inFirstCase = true;
  std::vector<FuncMemory*> ifState;
  ifStates[ifLevel] = ifState;

  map<MemoryAddr*,BranchStatus> madrState;
  madrStates[ifLevel] = madrState;
}

void MemoryLeakCheck::enterCurFunc(){
  if(!inFirstCase && inFirstIf){
    inFirstIf = false;
  }
  if(inFirstCase){
    inFirstCase = false;
  }

  onePath = nullptr;
  onePath = new FuncMemory(onePathTmp[ifLevel]);
}

void MemoryLeakCheck::enterSwitchScope(const clang::SwitchStmt *SS){
  ifLevel += 1;
  onePathTmp[ifLevel] = new FuncMemory(onePath);

  inFirstIf = true;
  inElseIf = false;
  inFirstCase = true;
  hasDefault[ifLevel] = false;
  std::vector<FuncMemory*> ifState;
  ifStates[ifLevel] = ifState;

  map<MemoryAddr*,BranchStatus> madrState;
  madrStates[ifLevel] = madrState;
}

void MemoryLeakCheck::enterCaseStmt(const clang::CaseStmt *CS){
  if(!inFirstCase && inFirstIf){
    inFirstIf = false;
  }
  if(inFirstCase){
    inFirstCase = false;
  }

  onePath = nullptr;
  onePath = new FuncMemory(onePathTmp[ifLevel]);
}

void MemoryLeakCheck::enterDefaultStmt(const clang::DefaultStmt *DS){
  hasDefault[ifLevel] = true;
  onePath = nullptr;
  onePath = new FuncMemory(onePathTmp[ifLevel]);
}

void MemoryLeakCheck::enterWhileScope(const clang::WhileStmt *WS){
  forLevel += 1;
  forPathTmp[forLevel] = new FuncMemory(onePath);
}

void MemoryLeakCheck::enterDoScope(const clang::DoStmt *DS){
  forLevel += 1;
  forPathTmp[forLevel] = new FuncMemory(onePath);
}

void MemoryLeakCheck::enterForScope(const clang::ForStmt *FS){
  forLevel += 1;
  forPathTmp[forLevel] = new FuncMemory(onePath);
}

void MemoryLeakCheck::finishIfScope(const clang::IfStmt *IS){
  ifLevel -= 1;
}

void MemoryLeakCheck::finishElseIfScope(const clang::IfStmt *IS){
  ifLevel += 1;
}

void MemoryLeakCheck::finishMultiFunc(){
  ifLevel -= 1;
}

void MemoryLeakCheck::finishSwitchScope(const clang::SwitchStmt *SS){
  hasDefault.erase(ifLevel+1);
  ifLevel -= 1;
}

void MemoryLeakCheck::finishWhileScope(const clang::WhileStmt *WS){
  if(BLOCKNAME == "MemoryLeakChecker") {
    handleLoopEnd();
  }

  forPathTmp[forLevel] = nullptr;
  forLevel -= 1;
}

void MemoryLeakCheck::finishDoScope(const clang::DoStmt *DS){
  if(BLOCKNAME == "MemoryLeakChecker") {
    handleLoopEnd();
  }

  forPathTmp[forLevel] = nullptr;
  forLevel -= 1;
}

void MemoryLeakCheck::finishForScope(const clang::ForStmt *FS){
  if(BLOCKNAME == "MemoryLeakChecker") {
    handleLoopEnd();
  }

  forPathTmp[forLevel] = nullptr;
  forLevel -= 1;
}

void MemoryLeakCheck::mergeFlow(){
  if(!inElseIf){
    if(ifStates.count(ifLevel) != 0 && onePathTmp[ifLevel] != nullptr){
      onePath = nullptr;
      onePath = new FuncMemory(onePathTmp[ifLevel]);
      std::vector<FuncMemory*> ifState = ifStates[ifLevel];
      map<MemoryAddr*,BranchStatus> madrSt = madrStates[ifLevel];

      for(auto mb_iter = madrSt.begin();
      mb_iter != madrSt.end();mb_iter++){
        if(mb_iter->second == BranchStatus::ALL_FREE){
          mb_iter->first->isreleased = true;
        } else if(mb_iter->second == BranchStatus::NO_FREE){
          mb_iter->first->isreleased = false;
        } else if(mb_iter->second == BranchStatus::POSSIBLE_FREE){
          if(BLOCKNAME == "MemoryLeakChecker") {
            mb_iter->first->isreleased = false;
          }

          if(BLOCKNAME == "DoubleFreeChecker") {
            mb_iter->first->isreleased = true;
          }
        }

        if(ifLevel > 0 && mb_iter->first->isreleased == true){
          if((onePath->mem[mb_iter->first->lineno]->isreleased == false)
          || (onePath->mem[mb_iter->first->lineno]->isreleased == true 
          && mb_iter->first->isjudged == true)){
            handleFreeState(ifLevel-1,mb_iter->first);            
          }
        }
      }

      for(auto fm_iter = ifState.begin();
      fm_iter != ifState.end();fm_iter++){
        map<std::string,std::vector<MemoryAddr*>> pointerSet = (*fm_iter)->pointerSet;
        map<int,MemoryAddr*> mem = (*fm_iter)->mem;
        map<std::string,MemoryPointer*> pointers = (*fm_iter)->pointers;

        for(auto ps_iter = pointers.begin();
        ps_iter != pointers.end();ps_iter++){
          if(onePath->pointers.count(ps_iter->first) == 0){
            onePath->pointers.insert(pair<std::string,MemoryPointer*>
            (ps_iter->first,new MemoryPointer(ps_iter->second)));
          }
        }

        for(auto mem_iter = mem.begin();
        mem_iter != mem.end();mem_iter++){
          if(onePath->mem.count(mem_iter->first) == 0){
            onePath->mem.insert(pair<int,MemoryAddr*>
            (mem_iter->first,mem_iter->second));
          } 
          if(mem_iter->second->isjudged == true){
            onePath->mem[mem_iter->first]->isreleased = mem_iter->second->beforejudged;
          }
          if(findMadr(madrSt,mem_iter->second)){
            MemoryAddr* mad_tmp = getMadr(madrSt,mem_iter->second);
            onePath->mem[mem_iter->first]->isreleased = mad_tmp->isreleased;
          }
        }

        for(auto ps_iter = pointerSet.begin();
        ps_iter != pointerSet.end();ps_iter++){
          if(onePath->pointerSet.count(ps_iter->first) == 0){
            onePath->pointerSet.insert(pair<std::string,std::vector<MemoryAddr*>>
            (ps_iter->first,ps_iter->second));
          } else {
            std::vector<MemoryAddr*> vm = ps_iter->second;
            std::vector<MemoryAddr*> curm = onePath->pointerSet[ps_iter->first];
            for(auto ma_iter = vm.begin();
            ma_iter != vm.end();ma_iter++){
              if(!findSameMem(curm,(*ma_iter))){
                onePath->pointerSet[ps_iter->first].push_back(*ma_iter);
              }
            }
          }
        }
      }

      ifStates.erase(ifLevel);
      madrStates.erase(ifLevel);
      onePathTmp[ifLevel] = nullptr;
    }
  }
}

void MemoryLeakCheck::handleIfCond(const clang::IfStmt *IS){
  const Expr *condexpr = IS->getCond();
  if (condexpr == nullptr)
    return;
  if (condexpr->getStmtClass() == Stmt::BinaryOperatorClass) {
    BinaryOperator *binaryOpExpr = 
      const_cast<BinaryOperator*>(dyn_cast<BinaryOperator>(condexpr));
    Expr *exprLHS = binaryOpExpr->getLHS();
    string lexp = getString_of_Expr(exprLHS);
    Expr *exprRHS = binaryOpExpr->getRHS();
    string rexp = getString_of_Expr(exprRHS);
    if (std::strcmp(rexp.c_str(), "((void *)0)") == 0
    || std::strcmp(rexp.c_str(), "__null") == 0) {
      QualType lexp_type = exprLHS->getType();
      if(isPointerOrReferenceType(lexp_type.getTypePtr())){
        if(onePath->pointers.count(lexp) > 0){
          unsigned ifCond = 0;
          if(binaryOpExpr->getOpcode() == BinaryOperatorKind::BO_EQ){
            ifCond = 1;
          } else if(binaryOpExpr->getOpcode() == BinaryOperatorKind::BO_NE){
            ifCond = 2;
          }

          if(ifCond == 1 || ifCond == 2){
            if(onePath->pointerSet.count(lexp) > 0){
              for(auto m_iter = onePath->pointerSet[lexp].begin();
              m_iter != onePath->pointerSet[lexp].end();++m_iter){
                if(ifCond == 1){
                  (*m_iter)->isreleased = true;
                } 
                if(ifCond == 2) {
                  //(*m_iter)->isreleased = false;
                  (*m_iter)->isjudged = true;
                }
              }
            }
            if(onePathTmp[ifLevel]->pointerSet.count(lexp) > 0){
              for(auto m_iter = onePathTmp[ifLevel]->pointerSet[lexp].begin();
              m_iter != onePathTmp[ifLevel]->pointerSet[lexp].end();++m_iter){
                // if(ifCond == 1){
                //   (*m_iter)->isreleased = false;
                // } 
                if (ifCond == 2) {
                  (*m_iter)->beforejudged = (*m_iter)->isreleased;
                  (*m_iter)->isreleased = true;
                }
              }
            }
          }
        }
      }
    }
  }
}

void MemoryLeakCheck::handleNoFree(){
  if(!inReturn){
    map<MemoryAddr*,BranchStatus> ifState = madrStates[ifLevel];
    for(auto states_iter = ifState.begin();
      states_iter != ifState.end();states_iter++){
        MemoryAddr* ma = states_iter->first;
        if(onePath->mem.count(ma->id) != 0 && onePathTmp[ifLevel]->mem.count(ma->id) != 0){
          if(onePath->mem[ma->id]->isreleased == false){
            if(states_iter->second == BranchStatus::ALL_FREE){
              if(!inFirstIf || !inFirstCase){
                states_iter->second = BranchStatus::POSSIBLE_FREE;
              }
            }
          }
        }
    }
    madrStates[ifLevel] = ifState;
  }
  inReturn = false;
}

void MemoryLeakCheck::handleNoElse(){
  map<MemoryAddr*,BranchStatus> ifState = madrStates[ifLevel];
  for(auto states_iter = ifState.begin();
    states_iter != ifState.end();states_iter++){
      if(states_iter->second == ALL_FREE){
        if(onePathTmp[ifLevel]->mem.count(states_iter->first->id) > 0
        && onePathTmp[ifLevel]->mem[states_iter->first->id]->isreleased == true){
          continue;
        }
        states_iter->second = BranchStatus::POSSIBLE_FREE;
      }
  }
  madrStates[ifLevel] = ifState;
}

void MemoryLeakCheck::handleFreeState(int ifLevel,MemoryAddr* madr){
  if(ifLevel >= 0 && onePathTmp[ifLevel]->mem.count(madr->id) == 0){
    return;
  }

  if(inFirstIf){
    madrStates[ifLevel].insert(pair<MemoryAddr*,BranchStatus>
    (new MemoryAddr(madr),BranchStatus::ALL_FREE));
  } else {
    if(findMadr(madrStates[ifLevel],madr)){
      MemoryAddr* ma_tmp = getMadr(madrStates[ifLevel],madr);
      if(madrStates[ifLevel][ma_tmp] == BranchStatus::NO_FREE){
        madrStates[ifLevel][ma_tmp] = BranchStatus::POSSIBLE_FREE;
      }
    } else {
      madrStates[ifLevel][madr] = BranchStatus::POSSIBLE_FREE;
    }
  }
}

void MemoryLeakCheck::handleLastFunc(){
  if(!inFirstCase){
    handleNoFree();
    ifStates[ifLevel].push_back(new FuncMemory(onePath));
  }
}

void MemoryLeakCheck::handleLastCase(){
  if(!inFirstCase){
    handleNoFree();
    ifStates[ifLevel].push_back(new FuncMemory(onePath));
  }
}

void MemoryLeakCheck::handleDefault(){
  handleLastCase();
  if(!hasDefault[ifLevel]){
    handleNoElse();
  }
  inElseIf = false;
}

void MemoryLeakCheck::handleReturn(){
  ifStates[0].push_back(new FuncMemory(onePath));
  onePath = nullptr;
  onePath = new FuncMemory(onePathTmp[ifLevel]);
  inFirstIf = false;
  inReturn = true;
}

void MemoryLeakCheck::handleFunctionEnd(){
  ifStates[0].push_back(new FuncMemory(onePath));
  mergeFlow();
}

void MemoryLeakCheck::handleLoopEnd(){
  for(auto pt_iter = onePath->pointerSet.begin();
  pt_iter != onePath->pointerSet.end();pt_iter++){
    std::vector<MemoryAddr*> madr = pt_iter->second;
      for(auto mem_iter = onePath->mem.begin();
      mem_iter != onePath->mem.end();mem_iter++){
        if(forPathTmp[forLevel]->mem.count(mem_iter->first) == 0){
          if(mem_iter->second->isreleased == false && 
          !inLeakReport(mem_iter->second->field,mem_iter->second->lineno)){
            string desc = "";
            desc += "Memory leak after variable " + pt_iter->first + " was changed";
            ReportSpace::Defect *def = new ReportSpace::Defect(LEAKTYPE,
                                                            ReportSpace::DefectType::Error,
                                                            mem_iter->second->field,
                                                            mem_iter->second->lineno, 
                                                            mem_iter->second->colno,
                                                            pt_iter->first);
            def->addDesc(desc);
            leakReport.push_back(def);
            addLeakReport(mem_iter->second->field,mem_iter->second->lineno);
          }
        }
      }
    }
}

void MemoryLeakCheck::handleFunctionPointer(FunctionDecl *FD) {
  if(FuncFp.count(FD) > 0){
    for(auto fname = FuncFp[FD].begin();fname != FuncFp[FD].end();++fname){
      if(FmName.count(*fname) > 0){
        FmName.erase(*fname);
      }
    }
  }
}

bool MemoryLeakCheck::findMadr(map<MemoryAddr*,BranchStatus> state,MemoryAddr* madr){
    for(auto ms_iter = state.begin();
    ms_iter != state.end();ms_iter++){
        MemoryAddr* ma = ms_iter->first;
        if(ma->field == madr->field 
        && ma->lineno == madr->lineno
        && ma->colno == madr->colno){
            return true;
        }
    }
    return false;
}

bool MemoryLeakCheck::findSameMem(std::vector<MemoryAddr*> curm,MemoryAddr* madr){
    for(auto ma_iter = curm.begin();
    ma_iter != curm.end();ma_iter++){
      if((*ma_iter)->field == madr->field
      && (*ma_iter)->lineno == madr->lineno
      && (*ma_iter)->colno == madr->colno
      && (*ma_iter)->isreleased == madr->isreleased){
        return true;
      } 
    }
    return false;
}

MemoryAddr* MemoryLeakCheck::getMadr(map<MemoryAddr*,BranchStatus> state,MemoryAddr* madr){
    for(auto ms_iter = state.begin();
    ms_iter != state.end();ms_iter++){
        MemoryAddr* ma = ms_iter->first;
        if(ma->field == madr->field 
        && ma->lineno == madr->lineno
        && ma->colno == madr->colno){
            return ma;
        }
    }
    return nullptr;
}

void MemoryLeakCheck::addLeakReport(std::string field,int line){
  stringstream ss;
  ss << field << line;
  leakHas.insert(pair<std::string,bool>(ss.str(),true));
}

bool MemoryLeakCheck::inLeakReport(std::string field,int line){
  stringstream ss;
  ss << field << line;
  string tmp = ss.str();
  if(leakHas.count(tmp) > 0){
    return true;
  }
  return false;
}